using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows.Input;
using Microsoft.Practices.Composite.Presentation.Commands;

namespace VocabCards
{
    public class WordProperties
    {
        public WordProperties()
        {
            _definitions = new List<Definition>();
        }

        public string Word { get; set; }
        private List<Definition> _definitions;
        public List<Definition> Definitions
        {
            get { return _definitions; }
        }

        private List<PosDefinitions> _posDefinitions;
        public List<PosDefinitions> PosDefinitions
        {
            get
            {
                return _posDefinitions ?? (_posDefinitions = CreatePosDefinitions());
            }
        }

        private string _synonyms;
        public string Synonyms
        {
            get { return _synonyms ?? (_synonyms = CreateString(d => d.Synonyms)); }
        }

        private string _antonyms;
        public string Antonyms
        {
            get { return _antonyms ?? (_antonyms = CreateString(d => d.Antonyms)); }
        }

        public void ResetSynAnt(int maxSynAnt)
        {
            _maxSynAnt = maxSynAnt;

            _antonyms = null;
            _synonyms = null;
        }

        private int _maxSynAnt = int.MaxValue;

        string CreateString(Func<Definition, IEnumerable<string>> selector)
        {

            var uqStrings = new Dictionary<string, string>();
            var builder = new StringBuilder();
            
            int selections = 0;

            _definitions.ForEach(d =>
                {
                    if (selector(d) != null)
                    foreach (var s in selector(d))
                    {
                        if (!uqStrings.ContainsKey(s) && s != Word && selections < _maxSynAnt)
                        {
                            selections++;
                            uqStrings.Add(s, s);

                            if (builder.Length > 0)
                            {
                                builder.Append(", ");
                            }

                            builder.Append(s);
                        }
                    }

                }
                );

            return builder.ToString();
        }

        private List<PosDefinitions> CreatePosDefinitions()
        {
            var defs = new List<PosDefinitions>();

            var poses = _definitions
                    .Select(definition => definition.PartOfSpeech)
                    .Distinct();


            foreach (var pos in poses)
            {
                var posDef = new PosDefinitions();
                posDef.PartOfSpeech = pos;

                foreach (var definition in Definitions.Where(d => d.PartOfSpeech == pos))
                {
                    posDef.Definitions.Add(definition);
                }

                defs.Add(posDef);
            }

            return defs;
        }
    }

    public class PosDefinitions
    {
        public string PartOfSpeech { get; set; }

        private readonly List<Definition> _definitions = new List<Definition>();
        public List<Definition> Definitions
        {
            get { return _definitions; }
        }

        private string _asString;
        public string AsString
        {
            get
            {
                if (_asString != null)
                    return _asString;

                _asString = PartOfSpeech + ": ";

                foreach (var definition in Definitions)
                {
                    _asString += definition.Def.Trim() + ". ";
                }

                return _asString;
            }
        }




        private ObservableCollection<StringHolder> _asStrings = new ObservableCollection<StringHolder>();
        public ObservableCollection<StringHolder> AsStrings
        {
            get {

                if (_asStrings.Count > 0)
                    return _asStrings;

                _asStrings.Add(new StringHolder(PartOfSpeech + ": ", -1)); ;

                int group = 0;

                foreach (var definition in Definitions)
                {
                    var g = ++group;

                    Action<object> deleteFunc = o =>
                                             _asStrings
                                                 .Where(sh => sh.Group == g)
                                                 .ToList()
                                                 .ForEach(holder => _asStrings.Remove(holder))
                        ;

                    var delCmd = new DelegateCommand<object>(deleteFunc);

                    definition.Def.Trim()
                        .Split(new []{' '})
                        .ToList()
                        .ForEach(s => 
                            
                            _asStrings.Add(
                            new StringHolder(s, group)
                                {
                                    Command = delCmd
                                }));

                    _asStrings.Add(
                        new StringHolder(".  ", group){Command = delCmd});
                }

                return _asStrings;

            }
        }
    }

    /// <summary>
    /// allows matching a specific string to a particular definition
    /// </summary>
    public class StringHolder 
    {
        public string TheString { get; set; }
        public int Group { get; set; }

        public StringHolder(string theString, int group)
        {
            TheString = theString;
            Group = group;
        }

        public ICommand Command { get; set; }
        public override string ToString()
        {
            return TheString;
        }
    }

    public class Definition
    {
        public string PartOfSpeech { get; set; }
        public string Def { get; set; }
        public List<string> Synonyms { get; set; }
        public List<string> Antonyms { get; set; }
    }
}